package com.AdvancedDemos.集合.单列集合;

import java.util.*;

public class LearnCollection {
    public static void main(String[] args) {
        /**
         * 集合体系结构
         *
         * 集合分为两大阵营:单列集合Collection 与 双列(键值对)集合Map
         *
         *Collection代表单列集合,每个元素(数据)包含一个值
         * Map代表双列集合,每个元素包含两个值(键值对)
         */

        /*
        List系列集合(ArrayList<E>,LinkedList<E>)添加的元素是有序的(队列),可重复的(元素可重复),有索引的(支持随机访问)

        Set系列集合中
        HashSet<E> 添加的元素是无序的,不重复的,无索引的 ,
        LinkedHashSet<E> 中的元素是有序的,不重复的,无索引的,
        TreeSet<E> 按照大小默认升序排序,不重复的,无索引的
        */

        /*
        Collection<E>本身是一个泛型接口,
        Collection<E>下面有两个常用的子接口List<E>和Set<E>,
        List<E>下面有实现类ArrayList<E>,LinkedList<E>
        Set<E>下面有实现类HashSet<E>,TreeSet<E>
        HashSet<E>下面有实现类LinkedHashSet<E>

    集合接口实现关系图:
                                Collection<E>         Map<E>
                            ↙                ↘
    接口- - - - - - -  List<E>                 Set<E>
                     ↙      ↘              ↙      ↘
    实现类- - ArrayList<E> LinkedList<E> HashSet<E> TreeSet<E>
                                            ↓
                                       LinkedHashSet<E>

         */
        //简单确认一下Collection集合的特点:
        ArrayList<String> list = new ArrayList<>();
        list.add("java1");
        list.add("java2");
        list.add("java1");
        list.add("java2");
        System.out.println(list);//[java1, java2, java1, java2] java2 可见ArrayList是有序的,可重复的
        System.out.println(list.get(1));//有索引的

        HashSet<String> set = new HashSet<>();
        set.add("java1");
        set.add("java2");
        set.add("java1");
        set.add("java2");
        set.add("java3");
        System.out.println(set);//[java3, java2, java1] 可见HashSet是无序的,不可重复的,无索引的


        /**
         * Collection中常用方法:
         * 1.public boolean add(E e) 添加元素,添加成功返回true,失败返回false
         * 2.public void clear() 清空集合的元素
         * 3.public boolean isEmpty() 判断集合是否为空,是空返回true,反之,返回false
         * 4.public int size() 获取集合的大小
         * 5.public boolean contains(Object obj) 判断集合中会否包含某个元素
         * 6.public boolean remove(E e) 删除某个元素,如果有多个重复元素,默认删除前面的第一个
         * 7.public Object[] toArray() 把集合转成数组
         * 8.把一个集合的全部数据添加另一个集合中去 c1.addAll(c2);//把c2集合中的全部数据添加到c1集合中去,c2集合原数据还在(应当注意两者泛型应当一致)
         */
        Collection<String> c = new ArrayList<>();//多态写法,父类变量指向子类对象
        System.out.println("---------------");
        //1.public boolean add(E e) 添加元素,添加成功返回true,失败返回false
        c.add("java1");
        c.add("java1");
        c.add("java2");
        c.add("java2");
        c.add("java3");
        System.out.println(c);//自动调用toString方法


        System.out.println("---------------");
        //2.public void clear() 清空集合的元素
        c.clear();
        System.out.println(c);


        System.out.println("---------------");
        //3.public boolean isEmpty() 判断集合是否为空,是空返回true,反之,返回false
        System.out.println("集合为空吗:" + c.isEmpty());
        c.add("java1");
        c.add("java1");
        c.add("java2");
        c.add("java2");
        c.add("java3");
        System.out.println(c);
        System.out.println("集合为空吗:" + c.isEmpty());


        System.out.println("---------------");
        //4.public int size() 获取集合的大小
        System.out.println("集合大小为:" + c.size());


        System.out.println("---------------");
        //5.public boolean contains(Object obj) 判断集合中会否包含某个元素
        System.out.println("是否包含\"java1\":" + c.contains("java1"));
        System.out.println("是否包含\"Java1\":" + c.contains("Java1"));


        System.out.println("---------------");
        //6.public boolean remove(E e) 删除某个元素,如果有多个重复元素,默认删除前面的第一个
        System.out.println("删除\"java1\":" + c.remove("java1"));
        System.out.println(c);


        System.out.println("---------------");
        //7.public Object[] toArray() 把集合转成数组
        Object[] arr = c.toArray();//默认返回Object数组
        System.out.println(Arrays.toString(arr));

        String[] strings = c.toArray(new String[c.size()]);//通过调用带参的toArray方法,可以将集合存到自己指定类型长度的数组中
        //借助toArray(T[] arr)
        //方法实际参数需要传递集合元素类型的数组
        //长度 < 集合元素个数 创建新的与集合元素个数相同的数组存储数据,如果将数组长度指定为0则意为只指定类型,长度等于集合元素
        //长度 >= 集合元素个数,直接使用参数数组存储数据
        System.out.println(Arrays.toString(strings));


        System.out.println("---------------");
        //8.把一个集合的全部数据添加另一个集合中去 c1.addAll(c2);//把c2集合中的全部数据添加到c1集合中去,c2集合原数据还在(应当注意两者泛型应当一致)
        Collection<String> c1 = new ArrayList<>();
        c1.add("java1");
        c1.add("java2");
        Collection<String> c2 = new ArrayList<>();
        c2.add("java3");
        c2.add("java4");
        c1.addAll(c2);//把c2集合中的全部数据添加到c1集合中去,c2集合原数据还在(应当注意两者泛型应当一致)
        System.out.println("c1:" + c1);
        System.out.println("c2:" + c2);


        /**
         * Collection的遍历方式:1.迭代器 2.增强for 3.forEach函数 + Lambda表达式
         * 不支持for循环,因为不是所有实现类都支持索引随机访问,Collection下面只有List系列才支持索引
         */


        //1.使用迭代器遍历集合元素
        //迭代器Iterator是用来遍历集合的专用方式(数组没有迭代器),在Java中迭代器的代表是Iterator
        //Collection集合获取迭代器的方法 Iterator<E> iterator --- 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的第一个元素
        //Iterator迭代器中的常用方法
        //boolean hasNext() --- 询问当前位置是否有元素在,存在返回true,不存在返回false
        //E next() --- 获取当前位置的元素,并同时将迭代器对象指向下一个元素处

        System.out.println("---------------");
        Collection<String> c3 = new ArrayList<>();
        c3.add("李荣浩");
        c3.add("周杰伦");
        c3.add("陈奕迅");
        c3.add("许嵩");
        System.out.println(c3);//[李荣浩, 周杰伦, 陈奕迅, 许嵩]

        Iterator<String> iterator = c3.iterator();//迭代器的泛型与集合的泛型一致,迭代器对象默认指向当前集合的第一个元素
        while (iterator.hasNext()) {//当前位置还有元素吗?
            String str = iterator.next();//当取元素次数超过集合元素个数时,会产生NoSuchElementException异常
            System.out.println(str);

            /*
            注意:每次循环hasNext判断一次,循环体中每次只能next往后取一次元素,如果取多次可能会因为取到了不存在的元素而报错NoSuchElementException
             */
        }


        //2.增强for循环(可以遍历数组/集合)
        /**
         * for(元素的数据类型 变量名 : 数组或者集合) {
         *
         * }
         * 如:
         * Collection<String> c = new ArrayList<>();
         * ...
         * for(String s : c){//意思是对集合c中每个String类型的元素s进行挨个处理
         *
         * }
         *
         * 增强for循环本质上就是迭代器遍历集合的简化写法
         */
        System.out.println("---------------");
        StringJoiner stringJoiner = new StringJoiner(" ", "[", "]");
        for (String ele : c3) {//ele就是一个游标,先后指向集合中每个元素
            stringJoiner.add(ele);
        }
        System.out.println(stringJoiner);

        String[] names = new String[]{"嘻嘻哈哈", "马尔扎哈", "噼里啪啦"};
        stringJoiner = new StringJoiner(" ", "[", "]");
        for (String name : names) {
            stringJoiner.add(name);
        }
        System.out.println(stringJoiner);


        //3.forEach函数 + Lambda表达式遍历集合
        /**
         * 需要使用Collection中的default void forEach(Consumer<? super T> action)方法才能使用Lambda表达式 , 该方法不在Collection接口中定义,而是在其父类Iterable中定义,forEach内部使用的就是增强for循环
         */
        System.out.println("---------------");
        c3.forEach(/*new Consumer<String>() {
            @Override
            public void accept(String s) {//s会依次指向集合中每一个元素
                System.out.println(s);
            }
        }*/
//                ↓简化
//                (String s) -> {System.out.println(s);}
//                ↓简化
//                s -> System.out.println(s)
//                ↓简化
                System.out::println
        );
    }
}
